iT邦幫忙

2021 iThome 鐵人賽

DAY 3
0
自我挑戰組

golang 後端菜雞工程師學習雜記系列 第 3

Day3 理解 golang slice 用法及原理 III

  • 分享至 

  • xImage
  •  

前兩篇寫了 slice 是什麼,以及創建 slice 的基本語法。

這篇就來寫 slice 的參數傳遞以及 append 到底做了什麼。

Slice 的參數傳遞

func pass(arr []int) {
    arr[0] = 4
}
a := []int{1, 2, 3}
pass(a)

看了這段程式,我們都知道 slice 的第一個元素被改為 4 了。

這時候就會有人說 slice 是 pass by refernece,但是 go 只有 pass by value,還記得 Day1 理解 golang slice 用法及原理 I 所說的 slice header 嗎,其實這個函式傳遞的是 slice header 的副本。slice 的第一個元素被更動,是因為兩個 slice header 指向了共同的 underying array。

看圖


再看一段程式

func pass(arr []int) {
    arr = []int{4, 5, 6}
}
a := []int{1, 2, 3}
pass(a)

arr 的更改並不會影響 a 的內容,因為兩個 slice header 指向不同的 underlying array


如果想讓 a 指向不同的 underyling array,應該要傳送 slice header 的地址。

func pass(arr *[]int) {
    arr = []int{4, 5, 6}
}
a := []int{1, 2, 3}
pass(&a)

append 做了什麼

先看一些兩個基本語法

將一個元素放進 slice 的最後一個元素

s := []int{1, 2, 3}
s = append(s, 1)

連接兩個 slice 的內容

s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
s1 = append(s1, s2...)

簡單的一個問題, slice 在 append 過後還指向同一個 underlying array 嗎? 還是分配了一塊新的?

在回答問題之前,先了解一下 append 的實作概念,Reference 1 給了一個很好的概念範例,這段範例給出了 append 設計的想法 (注意:這只是設計的概念)。(如果不熟 copy 怎麼使用,自己 google 一下囉)

func Append(slice []int, elements ...int) []int {
    n := len(slice)
    total := len(slice) + len(elements)
    if total > cap(slice) {
        // Reallocate. Grow to 1.5 times the new size, so we can still grow.
        newSize := total*3/2 + 1
        newSlice := make([]int, total, newSize)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[:total]
    copy(slice[n:], elements)
    return slice
}

還記得 Day2 理解 golang slice 用法及原理 II 礦泉水的例子嗎,假設想把兩瓶水裝成一瓶,如果本來瓶子容量夠大,把另一瓶水裝進來就好。如果裝不下,那就去找更大的瓶子,把這兩瓶水裝進去囉。至於為什麼乘 3 除 2 ,那不重要,這邊想表達的意思就是要找比原來兩個 slice 加起來還要大的容量。

懂了之後,回答原本的問題就很簡單了,答案是不一定。

文章索引

Reference

  1. Arrays, slices (and strings): The mechanics of 'append'

上一篇
Day2 理解 golang slice 用法及原理 II
下一篇
Day4 理解 golang slice 用法及原理 IV
系列文
golang 後端菜雞工程師學習雜記18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言